package main

import (
	"errors"
	"fmt"
)

/*
	“函数是一等的公民”是函数式编程（functional programming）的重要特征。

今天的问题是：怎样编写高阶函数？
	先来说说什么是高阶函数？简单地说，高阶函数可以满足下面的两个条件：
	1. 接受其他的函数作为参数传入；
	2. 把其他的函数作为结果返回。

问题 1：如何实现闭包？
	闭包又是什么？可以想象一下，在一个函数中存在对外来标识符的引用。
	所谓的外来标识符，既不代表当前函数的任何参数或结果，也不是函数内部声明的，它是直接从外边拿过来的。

	还有个专门的术语称呼它，叫自由变量，可见它代表的肯定是个变量。
	实际上，如果它是个常量，那也就形成不了闭包了，因为常量是不可变的程序实体，而闭包体现的却是由“不确定”变为“确定”的一个过程。


	type calculateFunc func(int, int) (int, error)

	func genCalculator(op operate) calculateFunc {
		return func(x int, y int) (int, error) {
			if op == nil {
				return 0, errors.New("invalid operation")
			}
			return op(x, y), nil
		}
	}

函数是Go语言支持函数式编程的主要体现。可以通过“把函数传给函数”以及“让函数返回函数”来编写高阶函数，也可以用高阶函数来实现闭包，并以此做到部分程序逻辑的动态生成。

*/

/*
	声明了一个函数类型，名叫Printer。
 */
type Printer func(content string) (num int, err error)

/*
	在func右边的就是这个函数类型的参数列表和结果列表。
 */
func printToStd(content string) (bytesNum int, err error)  {
	return fmt.Println(content)
}

/*
	声明一个名叫operate的函数类型，它有两个参数和一个结果，都是int类型的。
 */
type operate func(x,y int) int

/*
	该函数的结果应该有两个，一个是int类型的，代表真正的操作结果，另一个应该是error类型的，
	因为如果那个operate类型的参数值为nil，那么就应该直接返回一个错误。

	calculate函数就是一个高阶函数。但是说高阶函数的特点有两个，而该函数只展示了其中一个特点，即：接受其他的函数作为参数传入。
 */
func calculate(x int, y int, op operate) (int, error)  {
	if op == nil {
		return 0, errors.New("invalid operation")
	}
	return op(x,y), nil
}

/*
	genCalculator: 高阶函数
	1. 接受其他的函数作为参数传入。
	2. 把其他的函数作为结果返回
 */
func genCalculator(op operate) (operate, error) {
	if op == nil {
		return nil, errors.New("op is invalid")
	}
	return op, nil
}


type calculateFunc func(int, int) (int, error)

/*
	closureGenCalculator函数只做了一件事，那就是定义一个匿名的函数并把它作为结果值返回。而这个匿名的函数就是一个闭包函数。

 */
func closureGenCalculator(op operate) calculateFunc {
	return func(x int, y int) (int, error) {
		if op == nil {
			return 0, errors.New("invalid operation")
		}
		return op(x, y), nil
	}
}


func main() {

	var p Printer
	p = printToStd

	_, _ = p("something")

	op := func(x,y int) int {
		return x + y;
	}

	val, err := calculate(10, 20, op)
	if err != nil {
		fmt.Printf("The calculate error is : %s\n", err)
	}
	fmt.Printf("The calculate result is : %d \n", val)


	x, y := 56, 78
	calculator, err := genCalculator(op)
	if err != nil{
		fmt.Printf("The genCalculator error: %v \n", err)
	}
	value := calculator(x, y)
	fmt.Printf("The genCalculator result value is %d \n", value)

	/*
		闭包函数
	 */
	calculator02 := closureGenCalculator(op)
	value02, err := calculator02(x, y)

	if err != nil{
		fmt.Printf("The closureGenCalculator error: %v \n", err)
	}
	fmt.Printf("The closureGenCalculator result value02 is %d \n", value02)

}
